using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace WsdTestService.Discovery
{
    /// <summary>
    /// WSD发现服务（WS-Discovery协议）
    /// 监听UDP 3702端口，响应Windows客户端的Probe请求
    /// </summary>
    public class WsdDiscoveryService : IDisposable
    {
        private const int WsdPort = 3702;
        private static readonly IPAddress WsdMulticastAddress = IPAddress.Parse("239.255.255.250");
        private static readonly IPEndPoint WsdMulticastEndpoint = new IPEndPoint(WsdMulticastAddress, WsdPort);

        private UdpClient _udpClient;
        private bool _isDisposed;
        private bool _isRunning;
        private CancellationTokenSource _helloCancellationTokenSource;
        private Task _helloTask;

        private readonly string _deviceUuid;
        private readonly string _printerName;
        private readonly string _localIp;
        private readonly int _httpPort;
        private readonly string _printerUri;

        public WsdDiscoveryService(string deviceUuid, string printerName, string localIp, int httpPort, string printerUri)
        {
            _deviceUuid = deviceUuid;
            _printerName = printerName;
            _localIp = localIp;
            _httpPort = httpPort;
            _printerUri = printerUri;
        }

        /// <summary>
        /// 启动WSD发现服务
        /// </summary>
        public bool Start()
        {
            if (_isRunning)
                return true;

            try
            {
                _udpClient = new UdpClient();
                _udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
                
                // 设置广播选项（重要：发送多播消息需要）
                _udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true);

                // 绑定到本地端口3702
                _udpClient.Client.Bind(new IPEndPoint(IPAddress.Any, WsdPort));
                Console.WriteLine($"[WSD] UDP客户端已绑定到端口 {WsdPort}");

                // 加入多播组（重要：需要指定网络接口才能发送多播消息）
                // 获取本地IP地址对应的网络接口
                IPAddress localIpAddr = IPAddress.Parse(_localIp);
                Console.WriteLine($"[WSD] 准备加入多播组 {WsdMulticastAddress}:{WsdPort}，使用网络接口 {localIpAddr}");
                try
                {
                    // 尝试使用指定接口加入多播组
                    _udpClient.JoinMulticastGroup(WsdMulticastAddress, localIpAddr);
                    Console.WriteLine($"[WSD] ✓ 成功加入多播组，网络接口：{localIpAddr}");
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"[WSD] ⚠ 使用指定接口加入多播组失败: {ex.Message}，尝试使用默认方式...");
                    try
                    {
                        // 如果指定接口失败，尝试使用默认方式（不指定接口）
                        _udpClient.JoinMulticastGroup(WsdMulticastAddress);
                        Console.WriteLine($"[WSD] ✓ 使用默认方式成功加入多播组");
                    }
                    catch (Exception ex2)
                    {
                        Console.WriteLine($"[WSD] ✗ 加入多播组失败: {ex2.Message}");
                    throw;
                    }
                }

                // 设置多播TTL
                _udpClient.Ttl = 255;
                Console.WriteLine($"[WSD] 多播TTL已设置为 255");

                // 设置多播环回（允许接收自己发送的消息，用于测试）
                _udpClient.MulticastLoopback = true;

                // 启动异步接收循环
                _ = Task.Run(ReceiveLoop);

                // 先设置运行标志，这样SendHelloPeriodically才能执行
                _isRunning = true;

                // 启动定期发送Hello消息的任务（在_isRunning设置为true之后）
                _helloCancellationTokenSource = new CancellationTokenSource();
                _helloTask = Task.Run(() => SendHelloPeriodically(_helloCancellationTokenSource.Token));
                Console.WriteLine($"[WSD] 已加入多播组 {WsdMulticastAddress}:{WsdPort}");
                Console.WriteLine($"[WSD] 已启动定期Hello消息发送（每30秒）");
                return true;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[WSD] 启动失败: {ex.Message}");
                Dispose();
                return false;
            }
        }

        /// <summary>
        /// 停止WSD发现服务
        /// </summary>
        public void Stop()
        {
            if (!_isRunning)
                return;

            // 停止定期Hello消息发送
            try
            {
                _helloCancellationTokenSource?.Cancel();
                _helloTask?.Wait(TimeSpan.FromSeconds(1));
            }
            catch { }

            try
            {
                // 发送Bye消息（设备下线）
                SendBye();
            }
            catch { }

            _isRunning = false;
            Dispose();
        }

        /// <summary>
        /// 发送Hello消息（设备上线公告）
        /// Hello消息通过UDP多播发送到239.255.255.250:3702
        /// </summary>
        public void SendHello()
        {
            try
            {
                if (_udpClient == null || !_isRunning)
                {
                    Console.WriteLine($"[WSD] 无法发送Hello消息：UDP客户端未就绪或服务未运行");
                    return;
                }

                var helloMessage = BuildHelloMessage();
                var bytes = Encoding.UTF8.GetBytes(helloMessage);
                
                // 发送到多播地址（239.255.255.250:3702）
                Console.WriteLine($"[WSD] 正在发送Hello消息到多播地址 {WsdMulticastEndpoint}...");
                Console.WriteLine($"[WSD] UDP客户端状态：_udpClient={_udpClient != null}, _isRunning={_isRunning}");
                Console.WriteLine($"[WSD] 消息长度：{bytes.Length} 字节");
                
                try
                {
                int bytesSent = _udpClient.Send(bytes, bytes.Length, WsdMulticastEndpoint);
                
                if (bytesSent == bytes.Length)
                {
                    Console.WriteLine($"[WSD] ✓ Hello消息已成功发送（{bytesSent}/{bytes.Length} 字节）到 {WsdMulticastEndpoint}");
                }
                else
                {
                    Console.WriteLine($"[WSD] ⚠ Hello消息部分发送（{bytesSent}/{bytes.Length} 字节）到 {WsdMulticastEndpoint}");
                }
                }
                catch (Exception sendEx)
                {
                    Console.WriteLine($"[WSD] ✗ 发送Hello消息失败: {sendEx.Message}");
                    Console.WriteLine($"[WSD] 堆栈跟踪: {sendEx.StackTrace}");
                    throw;
                }
                
                // 只在调试时输出完整消息内容（避免日志过长）
                if (System.Diagnostics.Debugger.IsAttached)
                {
                Console.WriteLine($"[WSD] Hello消息内容：");
                Console.WriteLine(helloMessage);
                Console.WriteLine($"[WSD] --- Hello消息结束 ---");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[WSD] 发送Hello消息失败: {ex.Message}");
                Console.WriteLine($"[WSD] 堆栈跟踪: {ex.StackTrace}");
            }
        }

        /// <summary>
        /// 定期发送Hello消息（每30秒发送一次）
        /// Hello消息用于主动宣告设备存在，帮助Windows客户端发现设备
        /// 这是WSD协议中打印机发现的关键机制
        /// </summary>
        private async Task SendHelloPeriodically(CancellationToken cancellationToken)
        {
            // 等待UDP客户端和服务完全就绪
            await Task.Delay(2000, cancellationToken).ConfigureAwait(false);
            
            // 启动时立即发送一次
            if (!cancellationToken.IsCancellationRequested && _isRunning && _udpClient != null)
            {
                Console.WriteLine($"[WSD] 正在发送初始Hello消息...");
                SendHello();
            }

            // 然后每30秒发送一次
            while (!cancellationToken.IsCancellationRequested && _isRunning)
            {
                try
                {
                    await Task.Delay(TimeSpan.FromSeconds(30), cancellationToken).ConfigureAwait(false);
                    if (!cancellationToken.IsCancellationRequested && _isRunning && _udpClient != null)
                    {
                        Console.WriteLine($"[WSD] 定期发送Hello消息（每30秒）...");
                        SendHello();
                    }
                }
                catch (TaskCanceledException)
                {
                    break;
                }
                catch (Exception ex)
                {
                    if (_isRunning)
                    {
                        Console.WriteLine($"[WSD] 定期发送Hello消息时发生错误: {ex.Message}");
                        Console.WriteLine($"[WSD] 堆栈跟踪: {ex.StackTrace}");
                    }
                }
            }
        }

        /// <summary>
        /// 发送Bye消息（设备下线）
        /// </summary>
        private void SendBye()
        {
            try
            {
                var byeMessage = BuildByeMessage();
                var bytes = Encoding.UTF8.GetBytes(byeMessage);
                _udpClient?.Send(bytes, bytes.Length, WsdMulticastEndpoint);
                Console.WriteLine($"[WSD] Bye消息已发送");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[WSD] 发送Bye消息失败: {ex.Message}");
            }
        }

        /// <summary>
        /// 接收循环
        /// </summary>
        private async Task ReceiveLoop()
        {
            while (_isRunning && !_isDisposed && _udpClient != null)
            {
                try
                {
                    var result = await _udpClient.ReceiveAsync();
                    var message = Encoding.UTF8.GetString(result.Buffer);
                    var remoteEndpoint = result.RemoteEndPoint;

                    Console.WriteLine($"[WSD] 收到来自 {remoteEndpoint} 的消息（{result.Buffer.Length} 字节）");
                    
                    // 记录 Probe 请求的详细内容（用于调试）
                    if (IsProbeMessage(message))
                    {
                        Console.WriteLine($"[WSD] Probe请求内容（前500字符）：");
                        Console.WriteLine(message.Substring(0, Math.Min(500, message.Length)));
                        Console.WriteLine($"[WSD] Probe请求内容结束");
                    }

                    // 解析消息类型
                    if (IsProbeMessage(message))
                    {
                        Console.WriteLine($"[WSD] 检测到Probe请求，正在响应...");
                        var probeMatch = SendProbeMatch(message, remoteEndpoint);
                        Console.WriteLine($"[WSD] ProbeMatch完整响应内容：");
                        Console.WriteLine(probeMatch);
                        Console.WriteLine($"[WSD] ProbeMatch响应结束（{probeMatch.Length} 字符）");
                    }
                    else if (IsResolveMessage(message))
                    {
                        Console.WriteLine($"[WSD] 检测到Resolve请求，正在响应...");
                        var resolveMatch = SendResolveMatch(message, remoteEndpoint);
                        Console.WriteLine($"[WSD] ResolveMatch完整响应内容：");
                        Console.WriteLine(resolveMatch);
                        Console.WriteLine($"[WSD] ResolveMatch响应结束（{resolveMatch.Length} 字符）");
                    }
                    else
                    {
                        Console.WriteLine($"[WSD] 未知消息类型，前100字符：{message.Substring(0, Math.Min(100, message.Length))}");
                    }
                }
                catch (ObjectDisposedException)
                {
                    break;
                }
                catch (Exception ex)
                {
                    if (_isRunning)
                    {
                        Console.WriteLine($"[WSD] 接收消息时发生错误: {ex.Message}");
                    }
                }
            }
        }

        /// <summary>
        /// 检查是否是Probe消息
        /// </summary>
        private bool IsProbeMessage(string message)
        {
            var upperMessage = message.ToUpperInvariant();
            return upperMessage.IndexOf("PROBE", StringComparison.Ordinal) >= 0 &&
                   upperMessage.IndexOf("HTTP://SCHEMAS.XMLSOAP.ORG/WS/2005/04/DISCOVERY", StringComparison.Ordinal) >= 0;
        }

        /// <summary>
        /// 检查是否是Resolve消息
        /// </summary>
        private bool IsResolveMessage(string message)
        {
            var upperMessage = message.ToUpperInvariant();
            return upperMessage.IndexOf("RESOLVE", StringComparison.Ordinal) >= 0 &&
                   upperMessage.IndexOf("HTTP://SCHEMAS.XMLSOAP.ORG/WS/2005/04/DISCOVERY", StringComparison.Ordinal) >= 0;
        }

        /// <summary>
        /// 发送ProbeMatch响应
        /// </summary>
        private string SendProbeMatch(string probeMessage, IPEndPoint clientEndpoint)
        {
            try
            {
                var messageId = ExtractMessageId(probeMessage);
                
                // 检查Probe请求中是否有Types或Scopes过滤条件
                // 如果Windows请求特定的Types或Scopes，我们的响应必须匹配
                var requestedTypes = ExtractProbeTypes(probeMessage);
                var requestedScopes = ExtractProbeScopes(probeMessage);
                
                if (requestedTypes != null && requestedTypes.Count > 0)
                {
                    Console.WriteLine($"[WSD] Probe请求包含Types过滤: {string.Join(", ", requestedTypes)}");
                    // 检查我们的设备类型是否匹配
                    // 我们支持：wsdp:Device（通用设备）和 pws:PrintDeviceType（打印机设备）
                    var matches = requestedTypes.Any(t => 
                        t.IndexOf("PrintDeviceType", StringComparison.OrdinalIgnoreCase) >= 0 || 
                        t.IndexOf("print", StringComparison.OrdinalIgnoreCase) >= 0 ||
                        t.IndexOf("wsdp:Device", StringComparison.OrdinalIgnoreCase) >= 0 ||
                        t.IndexOf("Device", StringComparison.OrdinalIgnoreCase) >= 0);
                    
                    if (!matches)
                    {
                        Console.WriteLine($"[WSD] 注意：Probe请求的Types过滤不匹配我们的设备类型（{string.Join(", ", requestedTypes)}），但继续响应（因为我们支持通用设备类型）");
                    }
                    else
                    {
                        Console.WriteLine($"[WSD] ✓ Probe请求的Types过滤匹配我们的设备类型");
                    }
                }
                
                if (requestedScopes != null && requestedScopes.Count > 0)
                {
                    Console.WriteLine($"[WSD] Probe请求包含Scopes过滤: {string.Join(", ", requestedScopes)}");
                }
                
                var probeMatch = BuildProbeMatchMessage(messageId);
                var bytes = Encoding.UTF8.GetBytes(probeMatch);

                // 直接发送到客户端（单播），而不是多播
                _udpClient.Send(bytes, bytes.Length, clientEndpoint);
                Console.WriteLine($"[WSD] ProbeMatch响应已发送到 {clientEndpoint}");
                return probeMatch;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[WSD] 发送ProbeMatch响应失败: {ex.Message}");
                return string.Empty;
            }
        }
        
        /// <summary>
        /// 从Probe请求中提取Types过滤条件
        /// </summary>
        private List<string> ExtractProbeTypes(string probeMessage)
        {
            var types = new List<string>();
            try
            {
                // 查找 <wsd:Types> 或 <d:Types> 标签
                var patterns = new[] { "<wsd:Types>", "<d:Types>", "<Types>" };
                foreach (var pattern in patterns)
                {
                    var startTag = probeMessage.IndexOf(pattern, StringComparison.OrdinalIgnoreCase);
                    if (startTag >= 0)
                    {
                        startTag = probeMessage.IndexOf(">", startTag) + 1;
                        var endTag = probeMessage.IndexOf("</", startTag);
                        if (endTag > startTag)
                        {
                            var typesContent = probeMessage.Substring(startTag, endTag - startTag).Trim();
                            // Types可能包含多个值，用空格分隔
                            types.AddRange(typesContent.Split(new[] { ' ', '\t', '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries));
                        }
                    }
                }
            }
            catch { }
            return types;
        }
        
        /// <summary>
        /// 从Probe请求中提取Scopes过滤条件
        /// </summary>
        private List<string> ExtractProbeScopes(string probeMessage)
        {
            var scopes = new List<string>();
            try
            {
                // 查找 <wsd:Scopes> 或 <d:Scopes> 标签
                var patterns = new[] { "<wsd:Scopes>", "<d:Scopes>", "<Scopes>" };
                foreach (var pattern in patterns)
                {
                    var startTag = probeMessage.IndexOf(pattern, StringComparison.OrdinalIgnoreCase);
                    if (startTag >= 0)
                    {
                        startTag = probeMessage.IndexOf(">", startTag) + 1;
                        var endTag = probeMessage.IndexOf("</", startTag);
                        if (endTag > startTag)
                        {
                            var scopesContent = probeMessage.Substring(startTag, endTag - startTag).Trim();
                            // Scopes可能包含多个值，用空格分隔
                            scopes.AddRange(scopesContent.Split(new[] { ' ', '\t', '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries));
                        }
                    }
                }
            }
            catch { }
            return scopes;
        }

        /// <summary>
        /// 发送ResolveMatch响应
        /// </summary>
        private string SendResolveMatch(string resolveMessage, IPEndPoint clientEndpoint)
        {
            try
            {
                var messageId = ExtractMessageId(resolveMessage);
                var resolveMatch = BuildResolveMatchMessage(messageId);
                var bytes = Encoding.UTF8.GetBytes(resolveMatch);

                _udpClient.Send(bytes, bytes.Length, clientEndpoint);
                Console.WriteLine($"[WSD] ResolveMatch响应已发送到 {clientEndpoint}");
                return resolveMatch;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[WSD] 发送ResolveMatch响应失败: {ex.Message}");
                return string.Empty;
            }
        }

        /// <summary>
        /// 从SOAP消息中提取MessageID
        /// </summary>
        private string ExtractMessageId(string soapMessage)
        {
            try
            {
                // Windows可能使用 wsa:MessageID 或 a:MessageID，需要支持两种格式
                var patterns = new[] { "<wsa:MessageID>", "<a:MessageID>", "<MessageID>" };
                
                foreach (var pattern in patterns)
                {
                    var startTag = soapMessage.IndexOf(pattern, StringComparison.OrdinalIgnoreCase);
                if (startTag >= 0)
                {
                    startTag = soapMessage.IndexOf(">", startTag) + 1;
                    var endTag = soapMessage.IndexOf("</", startTag);
                    if (endTag > startTag)
                    {
                            var messageId = soapMessage.Substring(startTag, endTag - startTag).Trim();
                            // 确保返回完整的MessageID（包括urn:前缀，如果存在）
                            return messageId;
                        }
                    }
                }
            }
            catch { }

            // 如果无法提取，生成一个新的（使用urn:uuid格式以匹配Windows）
            return $"urn:uuid:{Guid.NewGuid():D}";
        }

        /// <summary>
        /// 构建Hello消息（设备上线公告）
        /// Hello消息应该在启动时和定期发送，以宣告设备存在
        /// </summary>
        private string BuildHelloMessage()
        {
            var hostname = Dns.GetHostName();
            // Windows期望MessageID使用urn:uuid格式
            var messageId = $"urn:uuid:{Guid.NewGuid():D}";
            // 与ProbeMatch保持一致，XAddrs包含Metadata端点和IPP端点
            var metadataUrl = $"http://{_localIp}:{_httpPort}/wsd/device/metadata";
            var xaddrs = $"{metadataUrl} {_printerUri}";

            // 关键修复：必须使用与Windows相同的命名空间版本（2004/2005）
            // Windows期望Types包含多个值：wsdp:Device（通用设备）和 pws:PrintDeviceType（打印机设备）
            return $@"<?xml version=""1.0"" encoding=""utf-8""?>
<s:Envelope xmlns:s=""http://www.w3.org/2003/05/soap-envelope""
            xmlns:wsa=""http://schemas.xmlsoap.org/ws/2004/08/addressing""
            xmlns:wsd=""http://schemas.xmlsoap.org/ws/2005/04/discovery""
            xmlns:pws=""http://schemas.microsoft.com/windows/2006/08/wdp/print""
            xmlns:wsdp=""http://schemas.xmlsoap.org/ws/2006/02/devprof"">
    <s:Header>
        <wsa:Action>http://schemas.xmlsoap.org/ws/2005/04/discovery/Hello</wsa:Action>
        <wsa:MessageID>{messageId}</wsa:MessageID>
        <wsa:To>urn:schemas-xmlsoap-org:ws:2005:04:discovery</wsa:To>
    </s:Header>
    <s:Body>
        <wsd:Hello>
            <wsa:EndpointReference>
                <wsa:Address>urn:uuid:{_deviceUuid}</wsa:Address>
            </wsa:EndpointReference>
            <wsd:Types>wsdp:Device pws:PrintDeviceType</wsd:Types>
            <wsd:Scopes>http://schemas.microsoft.com/windows/2006/08/wdp/print</wsd:Scopes>
            <wsd:XAddrs>{xaddrs}</wsd:XAddrs>
            <wsd:MetadataVersion>1</wsd:MetadataVersion>
        </wsd:Hello>
    </s:Body>
</s:Envelope>";
        }

        /// <summary>
        /// 构建Bye消息
        /// </summary>
        private string BuildByeMessage()
        {
            // Windows期望MessageID使用urn:uuid格式
            var messageId = $"urn:uuid:{Guid.NewGuid():D}";

            // 关键修复：必须使用与Windows相同的命名空间版本（2004/2005）
            return $@"<?xml version=""1.0"" encoding=""utf-8""?>
<s:Envelope xmlns:s=""http://www.w3.org/2003/05/soap-envelope""
            xmlns:wsa=""http://schemas.xmlsoap.org/ws/2004/08/addressing""
            xmlns:wsd=""http://schemas.xmlsoap.org/ws/2005/04/discovery"">
    <s:Header>
        <wsa:Action>http://schemas.xmlsoap.org/ws/2005/04/discovery/Bye</wsa:Action>
        <wsa:MessageID>{messageId}</wsa:MessageID>
        <wsa:To>urn:schemas-xmlsoap-org:ws:2005:04:discovery</wsa:To>
    </s:Header>
    <s:Body>
        <wsd:Bye>
            <wsa:EndpointReference>
                <wsa:Address>urn:uuid:{_deviceUuid}</wsa:Address>
            </wsa:EndpointReference>
        </wsd:Bye>
    </s:Body>
</s:Envelope>";
        }

        /// <summary>
        /// 构建ProbeMatch响应消息
        /// </summary>
        private string BuildProbeMatchMessage(string relatesToMessageId)
        {
            var hostname = Dns.GetHostName();
            // Windows期望MessageID使用urn:uuid格式
            var messageId = $"urn:uuid:{Guid.NewGuid():D}";
            // Windows期望Metadata URL，标准路径：/wsd/device/metadata
            // XAddrs可以包含多个地址，用空格分隔（Metadata端点和IPP端点）
            var metadataUrl = $"http://{_localIp}:{_httpPort}/wsd/device/metadata";
            var xaddrs = $"{metadataUrl} {_printerUri}";
            
            // 确保RelatesTo使用与Probe请求完全相同的MessageID格式
            // 如果Probe请求使用urn:uuid格式，RelatesTo也必须使用相同格式
            if (!relatesToMessageId.StartsWith("urn:", StringComparison.OrdinalIgnoreCase) && 
                relatesToMessageId.StartsWith("uuid:", StringComparison.OrdinalIgnoreCase))
            {
                relatesToMessageId = "urn:" + relatesToMessageId;
            }

            // 关键修复：必须使用与Windows Probe请求相同的命名空间版本（2004/2005）
            // Windows发送的是2004/2005版本，我们必须匹配，否则Windows会拒绝响应
            // Windows期望Types包含多个值：wsdp:Device（通用设备）和 pws:PrintDeviceType（打印机设备）
            return $@"<?xml version=""1.0"" encoding=""utf-8""?>
<s:Envelope xmlns:s=""http://www.w3.org/2003/05/soap-envelope""
            xmlns:wsa=""http://schemas.xmlsoap.org/ws/2004/08/addressing""
            xmlns:wsd=""http://schemas.xmlsoap.org/ws/2005/04/discovery""
            xmlns:pws=""http://schemas.microsoft.com/windows/2006/08/wdp/print""
            xmlns:wsdp=""http://schemas.xmlsoap.org/ws/2006/02/devprof"">
    <s:Header>
        <wsa:Action>http://schemas.xmlsoap.org/ws/2005/04/discovery/ProbeMatches</wsa:Action>
        <wsa:MessageID>{messageId}</wsa:MessageID>
        <wsa:RelatesTo>{relatesToMessageId}</wsa:RelatesTo>
        <wsa:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To>
    </s:Header>
    <s:Body>
        <wsd:ProbeMatches>
            <wsd:ProbeMatch>
                <wsa:EndpointReference>
                    <wsa:Address>urn:uuid:{_deviceUuid}</wsa:Address>
                </wsa:EndpointReference>
                <wsd:Types>wsdp:Device pws:PrintDeviceType</wsd:Types>
                <wsd:Scopes>http://schemas.microsoft.com/windows/2006/08/wdp/print</wsd:Scopes>
                <wsd:XAddrs>{xaddrs}</wsd:XAddrs>
                <wsd:MetadataVersion>1</wsd:MetadataVersion>
            </wsd:ProbeMatch>
        </wsd:ProbeMatches>
    </s:Body>
</s:Envelope>";
        }

        /// <summary>
        /// 构建ResolveMatch响应消息
        /// </summary>
        private string BuildResolveMatchMessage(string relatesToMessageId)
        {
            var hostname = Dns.GetHostName();
            // Windows期望MessageID使用urn:uuid格式
            var messageId = $"urn:uuid:{Guid.NewGuid():D}";
            // Windows期望Metadata URL，标准路径：/wsd/device/metadata
            // XAddrs可以包含多个地址，用空格分隔（Metadata端点和IPP端点）
            var metadataUrl = $"http://{_localIp}:{_httpPort}/wsd/device/metadata";
            var xaddrs = $"{metadataUrl} {_printerUri}";
            
            // 确保RelatesTo使用与Resolve请求完全相同的MessageID格式
            if (!relatesToMessageId.StartsWith("urn:", StringComparison.OrdinalIgnoreCase) && 
                relatesToMessageId.StartsWith("uuid:", StringComparison.OrdinalIgnoreCase))
            {
                relatesToMessageId = "urn:" + relatesToMessageId;
            }

            // 关键修复：必须使用与Windows相同的命名空间版本（2004/2005）
            // Windows期望Types包含多个值：wsdp:Device（通用设备）和 pws:PrintDeviceType（打印机设备）
            return $@"<?xml version=""1.0"" encoding=""utf-8""?>
<s:Envelope xmlns:s=""http://www.w3.org/2003/05/soap-envelope""
            xmlns:wsa=""http://schemas.xmlsoap.org/ws/2004/08/addressing""
            xmlns:wsd=""http://schemas.xmlsoap.org/ws/2005/04/discovery""
            xmlns:pws=""http://schemas.microsoft.com/windows/2006/08/wdp/print""
            xmlns:wsdp=""http://schemas.xmlsoap.org/ws/2006/02/devprof"">
    <s:Header>
        <wsa:Action>http://schemas.xmlsoap.org/ws/2005/04/discovery/ResolveMatches</wsa:Action>
        <wsa:MessageID>{messageId}</wsa:MessageID>
        <wsa:RelatesTo>{relatesToMessageId}</wsa:RelatesTo>
        <wsa:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To>
    </s:Header>
    <s:Body>
        <wsd:ResolveMatches>
            <wsd:ResolveMatch>
                <wsa:EndpointReference>
                    <wsa:Address>urn:uuid:{_deviceUuid}</wsa:Address>
                </wsa:EndpointReference>
                <wsd:Types>wsdp:Device pws:PrintDeviceType</wsd:Types>
                <wsd:Scopes>http://schemas.microsoft.com/windows/2006/08/wdp/print</wsd:Scopes>
                <wsd:XAddrs>{xaddrs}</wsd:XAddrs>
                <wsd:MetadataVersion>1</wsd:MetadataVersion>
            </wsd:ResolveMatch>
        </wsd:ResolveMatches>
    </s:Body>
</s:Envelope>";
        }

        public void Dispose()
        {
            if (_isDisposed)
                return;

            _isDisposed = true;
            _isRunning = false;

            // 停止定期Hello消息发送
            try
            {
                _helloCancellationTokenSource?.Cancel();
                _helloTask?.Wait(TimeSpan.FromSeconds(2));
                _helloCancellationTokenSource?.Dispose();
            }
            catch { }

            try
            {
                if (_udpClient != null)
                {
                    // .NET Framework 的 DropMulticastGroup 只接受一个参数（多播地址）
                    _udpClient.DropMulticastGroup(WsdMulticastAddress);
                }
            }
            catch { }

            try
            {
                _udpClient?.Close();
            }
            catch { }

            _udpClient?.Dispose();
            _udpClient = null;
        }
    }
}

